import Foundation
import AVFoundation
import UIKit
import CoreMotion

public struct CameraKitNotice {
    public static let cameraKitDeviceOrientationNotice = Notification.Name("cameraKitDeviceOrientationNotice")
}

open class Orientation {

    public var shouldUseDeviceOrientation: Bool  = true

    private let coreMotionManager = CMMotionManager()
    private var deviceOrientation: UIDeviceOrientation?

   public init() {
        coreMotionManager.accelerometerUpdateInterval = 0.1
    }

    public func start() {
        self.deviceOrientation = UIDevice.current.orientation
        coreMotionManager.startAccelerometerUpdates(to: .main) { [weak self] (data, _) in
            guard let data = data else {
                return
            }
            self?.handleAccelerometerUpdate(data: data)
        }
    }

    public func stop() {
        self.coreMotionManager.stopAccelerometerUpdates()
        self.deviceOrientation = nil
    }

    public func getImageOrientation() -> UIImage.Orientation {
        guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return .right }
        switch deviceOrientation {
        case .landscapeLeft:
            return .up
        case .landscapeRight:
            return .down
        case .portraitUpsideDown:
            return .left
        default:
            return .right
        }
    }

    public func getPreviewLayerOrientation() -> AVCaptureVideoOrientation {
        switch UIApplication.shared.statusBarOrientation {
        case .portrait, .unknown:
            return AVCaptureVideoOrientation.portrait
        case .landscapeLeft:
            return AVCaptureVideoOrientation.landscapeLeft
        case .landscapeRight:
            return AVCaptureVideoOrientation.landscapeRight
        case .portraitUpsideDown:
            return AVCaptureVideoOrientation.portraitUpsideDown
        @unknown default:
            return AVCaptureVideoOrientation.portrait
        }
    }

    public func getVideoOrientation() -> AVCaptureVideoOrientation? {
        guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return nil }
        switch deviceOrientation {
        case .landscapeLeft:
            return .landscapeRight
        case .landscapeRight:
            return .landscapeLeft
        case .portraitUpsideDown:
            return .portraitUpsideDown
        default:
            return .portrait
        }
    }

    private func handleAccelerometerUpdate(data: CMAccelerometerData) {
        if abs(data.acceleration.y) < abs(data.acceleration.x) {
            if data.acceleration.x > 0 {
                deviceOrientation = UIDeviceOrientation.landscapeRight
            } else {
                deviceOrientation = UIDeviceOrientation.landscapeLeft
            }
        } else {
            if data.acceleration.y > 0 {
                deviceOrientation = UIDeviceOrientation.portraitUpsideDown
            } else {
                deviceOrientation = UIDeviceOrientation.portrait
            }
        }
        NotificationCenter.default.post(name: CameraKitNotice.cameraKitDeviceOrientationNotice,
                                        object: nil,
                                        userInfo: [CameraKitNotice.cameraKitDeviceOrientationNotice.rawValue: String(deviceOrientation!.rawValue)])
    }
}
